<template>
    <div class="_blockbreakercontent">
        <canvas class="blockbreakercanvas"></canvas>
        <button class="blockbreakerstart" @click="start()">START</button>
    </div>
</template>

<script setup>
class blockclass {
    constructor(_x, _y, _color) {
        this.x = _x;
        this.y = _y;
        this.color = _color;
    }
}
class board {
    constructor(_x, _y, _long = 100) {
        this.x = _x;
        this.y = _y;
        this.long = _long;

    }
}
class ball {
    vx = null; vy = null;
    constructor(_sx, _sy, _color = "white") {
        this.sx = _sx;
        this.sy = _sy;
        this.color = _color;
    }
}
class canvasanimotion {
    canvas = null;
    ctx = null;
    board = null;//移动板
    blocks = [] //砖块数组
    colors = [ //颜色数组
        "#eccc68",
        "#ff7f50",
        "#ff6b81",
        "#7bed9f",
        "#5352ed",
        "#70a1ff"
    ]
    speed = 0.3 //弹球移动速度
    run = null
    fires = [] //烟火数组
    score = 0 //分数
    rungame = false //默认运行状态
    interval = null
    constructor() {
        this.canvas = document.querySelector(".blockbreakercanvas")
        this.ctx = this.canvas.getContext("2d")
        let tempRect = document.querySelector('._blockbreakercontent').getBoundingClientRect()

        if (tempRect.height < 200)
            document.querySelector('._blockbreakercontent').style = 'height:500px !important;';
        this.canvas.width = tempRect.width;
        this.canvas.height = tempRect.height < 100 ? 500 : tempRect.height;
        this.run = document.querySelector(".blockbreakerstart")
        this.board = new board(0, this.canvas.height - 20)
    }
    newgame() {

        this.ball = new ball(this.canvas.width / 2, this.canvas.height / 2)
        this.ball.vx = (0.5 - Math.random()) * this.speed
        this.ball.vy = Math.sqrt(this.speed * this.speed - this.ball.vx * this.ball.vx)
        this.score = 0
        this.blocks = []
        for (var i = 0; i < Math.floor(this.canvas.width / 80); i++) { //生成砖块
            for (var j = 0; j < Math.floor(this.canvas.height / 2 / 30); j++) {
                this.blocks.push(new blockclass(i, j, this.colors[parseInt(Math.random() * this.colors.length)]))
            }
        }
        this.cRect = this.canvas.getBoundingClientRect()
        let that = this
        window.addEventListener("mousemove", function (evt) { //移动鼠标变更反弹板位置
            var x = evt.clientX - that.cRect.left

            if (x < that.board.long) {
                that.board.x = 0
            } else if (x > that.canvas.width) {
                that.board.x = that.canvas.width - that.board.long
            } else {
                that.board.x = x - that.board.long
            }
        })
    }
    draw() {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)


        for (var i = 0; i < this.blocks.length; i++) { //绘制砖块
            let block = this.blocks[i]
            this.ctx.fillStyle = block.color
            this.ctx.fillRect(block.x * 80 + 1, block.y * 30 + 1, 79, 29)
            if (this.ball.sx + 10 > block.x * 80 + 1 && this.ball.sx - 10 < block.x * 80 + 80 && this.ball.sy + 10 > block.y * 30 + 1 && this.ball.sy - 10 < block.y * 30 + 30) { //砖块碰撞判断

                if (this.ball.sx > block.x * 80 + 80 || this.ball.sx < block.x * 80) { //左右方向碰撞则改变x轴运行方向
                    this.ball.vx = -this.ball.vx
                } else if (this.ball.sy > block.y * 30 + 30 || this.ball.sy < block.y * 30) { //垂直方向碰撞则改变Y轴运行方向
                    this.ball.vy = -this.ball.vy
                }
                if (this.ball.color == block.color) { //同色碰撞则加10分
                    this.score += 10
                } else { //非同色碰撞加1分
                    this.score++
                }
                this.ball.color = block.color //撞击后球的颜色变成砖块颜色
                this.blocks.splice(i, 1) //碰撞后砖块消失
                for (var f = 0; f < 50; f++) { //生成火花
                    this.fires.push({
                        sx: block.x * 80 + 40,
                        sy: block.y * 30 + 15,
                        color: block.color,
                        vx: 0.5 - Math.random(),
                        vy: 0.5 - Math.random(),
                        age: 100
                    })
                }
            }
        }
        this.ctx.fillStyle = "white" //绘制分数
        this.ctx.font = "20px sans-serif"
        this.ctx.fillText(this.score, 5, 25)
        this.ctx.fillRect(this.board.x, this.board.y, this.board.long, 20) //绘制反弹板
        this.ctx.beginPath() //绘制小球
        this.ctx.fillStyle = this.ball.color
        this.ctx.arc(this.ball.sx, this.ball.sy, 10, 0, 2 * Math.PI)
        this.ctx.fill()

        if (this.rungame) { //判断游戏运行状态，并刷新球的位置
            this.ball.sx += this.ball.vx * 5
            this.ball.sy += this.ball.vy * 5
            if (this.ball.sy < 10) { //上边缘碰撞判断
                this.ball.vy = -this.ball.vy
            }
            if (this.ball.sx < 10 || this.ball.sx > 795) { //左右碰撞判断
                this.ball.vx = -this.ball.vx
            }
            if (this.ball.sy > this.board.y && this.ball.sx > this.board.x && this.ball.sx < this.board.x + this.board.long) { //反弹板碰撞判断
                this.ball.vx = (this.ball.sx - (this.board.x + this.board.long / 2)) / this.board.long / 2 * this.speed * 3
                this.ball.vy = -Math.sqrt(this.speed * this.speed - this.ball.vx * this.ball.vx)
                this.speed = this.speed * 1.001
                for (var f = 0; f < 20; f++) {
                    this.fires.push({
                        sx: this.ball.sx,
                        sy: this.ball.sy + 10,
                        color: this.colors[parseInt(Math.random() * this.colors.length)],
                        vx: 0.5 - Math.random(),
                        vy: Math.random() - 1,
                        age: 60
                    })
                }

            }
            if (this.ball.sy > (this.board.y + 20) || this.blocks.length <= 0) { //碰撞到底部或所有砖块都消失则游戏停止运行
                this.rungame = false
                this.run.style.display = "flex"
                this.canvas.style.cursor = "default"
                for (var f = 0; f < 150; f++) {
                    this.fires.push({
                        sx: 400,
                        sy: 300,
                        color: this.colors[parseInt(Math.random() * this.colors.length)],
                        vx: 0.5 - Math.random(),
                        vy: 0.5 - Math.random(),
                        age: 560
                    })
                }
            }
        }
        for (var i = 0; i < this.fires.length; i++) {
            let fire = this.fires[i]
            this.ctx.fillStyle = fire.color
            this.ctx.fillRect(fire.sx, fire.sy, 2, 2)
            fire.age--
            if (fire.age < 0) {
                this.fires.splice(i, 1)
            }
            fire.sx += fire.vx * 2
            fire.sy += fire.vy * 2
        }
        if (!this.rungame)
            clearInterval(this.interval)
    }
    start() {
        this.newgame()
        this.rungame = true
        this.run.style.display = "none"
        this.canvas.style.cursor = "none"
        this.interval = setInterval(() => {
            this.draw()
        }, 1);
    }
}

let start = () => {
    let game = new canvasanimotion()
    game.start()
}
</script>

<style lang="scss" scoped>
._blockbreakercontent {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 10px;
    overflow: hidden;
    background: #333;
    position: relative;
    .blockbreakercanvas {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        border: 1px solid white;
        /* cursor:none; */
        filter: drop-shadow(0 0 2px white);
    }

    .blockbreakerstart {
        position: absolute;
        width: 120px;
        height: 40px;

        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        font-size: 28px;
        padding: 5px;
        border-radius: 4px;
        display: flex;
        background: rgba(255, 255, 255, 0.4);
        justify-content: center;
    }
}
</style>